hyperloglog-rs 0.1.56

A Rust implementation of HyperLogLog trying to be parsimonious with memory.
Documentation
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "36638c1d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>precision</th>\n",
       "      <th>bits</th>\n",
       "      <th>exact</th>\n",
       "      <th>hll</th>\n",
       "      <th>mle</th>\n",
       "      <th>nn</th>\n",
       "      <th>memory</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>42156</td>\n",
       "      <td>34932.480</td>\n",
       "      <td>35220.203</td>\n",
       "      <td>32249.0760</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>41286</td>\n",
       "      <td>38823.050</td>\n",
       "      <td>39088.293</td>\n",
       "      <td>35839.3200</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>50193</td>\n",
       "      <td>48058.280</td>\n",
       "      <td>47923.758</td>\n",
       "      <td>44361.6560</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>43799</td>\n",
       "      <td>42339.727</td>\n",
       "      <td>42611.395</td>\n",
       "      <td>39084.5350</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>11477</td>\n",
       "      <td>11385.202</td>\n",
       "      <td>11410.331</td>\n",
       "      <td>10519.4770</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>995</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>3591</td>\n",
       "      <td>3524.602</td>\n",
       "      <td>3528.330</td>\n",
       "      <td>3265.6584</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>996</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>10913</td>\n",
       "      <td>10343.806</td>\n",
       "      <td>10379.179</td>\n",
       "      <td>9558.4690</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>997</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>26735</td>\n",
       "      <td>24805.870</td>\n",
       "      <td>25014.912</td>\n",
       "      <td>22904.1660</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>998</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>20049</td>\n",
       "      <td>19638.902</td>\n",
       "      <td>19761.277</td>\n",
       "      <td>18136.0500</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>999</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>15690</td>\n",
       "      <td>15910.534</td>\n",
       "      <td>15972.994</td>\n",
       "      <td>14695.4850</td>\n",
       "      <td>1536</td>\n",
       "      <td>HLL</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>1000 rows × 8 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "     precision  bits  exact        hll        mle          nn  memory label\n",
       "0            8     6  42156  34932.480  35220.203  32249.0760    1536   HLL\n",
       "1            8     6  41286  38823.050  39088.293  35839.3200    1536   HLL\n",
       "2            8     6  50193  48058.280  47923.758  44361.6560    1536   HLL\n",
       "3            8     6  43799  42339.727  42611.395  39084.5350    1536   HLL\n",
       "4            8     6  11477  11385.202  11410.331  10519.4770    1536   HLL\n",
       "..         ...   ...    ...        ...        ...         ...     ...   ...\n",
       "995          8     6   3591   3524.602   3528.330   3265.6584    1536   HLL\n",
       "996          8     6  10913  10343.806  10379.179   9558.4690    1536   HLL\n",
       "997          8     6  26735  24805.870  25014.912  22904.1660    1536   HLL\n",
       "998          8     6  20049  19638.902  19761.277  18136.0500    1536   HLL\n",
       "999          8     6  15690  15910.534  15972.994  14695.4850    1536   HLL\n",
       "\n",
       "[1000 rows x 8 columns]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "df = pd.read_csv(\"cardinality_benchmark.tsv\", sep=\"\\t\")\n",
    "\n",
    "df[\"memory\"] = 2**df.precision * df.bits\n",
    "df[\"label\"] = \"HLL\"\n",
    "\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "f063b87f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.484"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "samples = pd.read_csv(\"experiments/cardinality_model/samples.tsv\", sep=\"\\t\")\n",
    "\n",
    "samples[\"mse_rates\"] = ((samples.ground - samples.model)**2 / (samples.ground - samples.hll)**2)\n",
    "\n",
    "(samples[\"mse_rates\"] > 1.0).mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "1c4b5422",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: >"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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a9as6b5u37595ZqamvJvf/vbDCYcHI6cDEChUIiJEydGQ0NDPP744/362GeObcuWLfHZz342Jk2a1H3dwoULo729Pf75z39mOFn+rF69Os4555y46qqrYs2aNZ4aG4BDhw7FG2+8EQsWLOi+rrq6OhYsWBBbtmzJcLLh4Z133on6+vq4+OKL4xvf+Ebs2rUr65GGlR07dsSePXt63H/Hjx8fjY2Nub7/5u6D/7Jy3333xZe//OWora2Nl156Kb7//e/H/v3747bbbst6tNzas2dPjzCJiO7Le/bsyWKkXLrtttvic5/7XEyYMCE2b94cd999d7z33nvxyCOPZD1aLuzduzdKpVKf98W33noro6mGh8bGxli/fn1ceuml8d5778W9994bX/rSl+If//hHjBs3LuvxhoUjj5V93X/z/Dg6bI+cLF++vM8Xsf7vn4E88Nxzzz3xxS9+Ma666qr48Y9/HHfddVesWbOmgt9BmgZ7XenbQNa5ubk55s2bF1deeWV897vfjYcffjgeffTR6OjoyPi7YKRbtGhR3HjjjXHllVfGwoUL4/nnn499+/bF73//+6xHI3HD9sjJHXfcEd/61reOe5uLL774pLff2NgY999/f3R0dAzLzzU4lsFc18mTJx91RkRbW1v310ayU1nnxsbGOHz4cOzcuTMuvfTSCkw3vEycODFGjRrVfd87oq2tbcTfDwfbWWedFZ/+9Kdj+/btWY8ybBy5j7a1tcX555/ffX1bW1vMmjUro6lO3bCNk3PPPTfOPffcim1/27ZtcfbZZ4+oMIkY3HW9+uqr44EHHoj3338/zjvvvIiI2LhxY9TV1cWMGTMGZR95dSrrvG3btqiuru5eU45vzJgxMXv27Ni0aVP3GXhdXV2xadOmWLZsWbbDDTP79++Pf/3rX3HzzTdnPcqwcdFFF8XkyZNj06ZN3THS3t4er7322gnPQE3ZsI2Tgdi1a1f897//jV27dkWpVIpt27ZFRMSnPvWpOPPMM+OPf/xjtLW1xec///kYO3ZsbNy4MR588MG48847sx08cSda12uvvTZmzJgRN998czz00EOxZ8+e+MlPfhKFQmHERd/J2rJlS7z22msxf/78GDduXGzZsiV++MMfxje/+c04++yzsx4vN5qbm6OpqSnmzJkTDQ0NsXbt2jhw4EDccsstWY+Wa3feeWcsWbIkLrzwwti9e3esXLkyRo0aFV//+tezHi1X9u/f3+No044dO2Lbtm0xYcKEmDZtWtx+++3x05/+NC655JK46KKL4p577on6+vp8v91F1qcLpaCpqakcEUf9efnll8vlcrn85z//uTxr1qzymWeeWT7jjDPKM2fOLK9bt65cKpWyHTxxJ1rXcrlc3rlzZ3nRokXl008/vTxx4sTyHXfcUe7s7Mxu6Jx54403yo2NjeXx48eXx44dW77sssvKDz74YPnjjz/OerTcefTRR8vTpk0rjxkzptzQ0FD+29/+lvVIubd06dLy+eefXx4zZkx5ypQp5aVLl5a3b9+e9Vi58/LLL/f5WNrU1FQulz85nfiee+4pT5o0qVxTU1P+yle+Un777bezHfoUVZXLzocFANIxbM/WAQDySZwAAEkRJwBAUsQJAJAUcQIAJEWcAABJEScAQFLECQCQFHECACRFnAAASREnAEBSxAkAkJT/A1wr/XSOqgWGAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "samples.mse_rates.hist(log=True, bins=100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "688ead39",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr th {\n",
       "        text-align: left;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th>precision</th>\n",
       "      <th>bits</th>\n",
       "      <th>memory</th>\n",
       "      <th colspan=\"2\" halign=\"left\">squared_error_hll</th>\n",
       "      <th colspan=\"2\" halign=\"left\">squared_error_mle</th>\n",
       "      <th colspan=\"2\" halign=\"left\">squared_error_nn</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>mean</th>\n",
       "      <th>std</th>\n",
       "      <th>mean</th>\n",
       "      <th>std</th>\n",
       "      <th>mean</th>\n",
       "      <th>std</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>1536</td>\n",
       "      <td>0.004652</td>\n",
       "      <td>0.005434</td>\n",
       "      <td>0.00442</td>\n",
       "      <td>0.005189</td>\n",
       "      <td>0.015637</td>\n",
       "      <td>0.014054</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  precision bits memory squared_error_hll           squared_error_mle  \\\n",
       "                                     mean       std              mean   \n",
       "0         8    6   1536          0.004652  0.005434           0.00442   \n",
       "\n",
       "            squared_error_nn            \n",
       "        std             mean       std  \n",
       "0  0.005189         0.015637  0.014054  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[\"hll\"] /= df.exact\n",
    "df[\"mle\"] /= df.exact\n",
    "df[\"nn\"] /= df.exact\n",
    "df[\"exact\"] /= df.exact\n",
    "df[\"squared_error_hll\"] = (df.exact - df.hll)**2\n",
    "df[\"squared_error_mle\"] = (df.exact - df.mle)**2\n",
    "df[\"squared_error_nn\"] = (df.exact - df.nn)**2\n",
    "columns = [\"squared_error_hll\", \"squared_error_mle\", \"squared_error_nn\"]\n",
    "data_hll = df.groupby([\"precision\", \"bits\", \"memory\"])[columns].agg([\"mean\", \"std\"])\n",
    "data_hll = data_hll.reset_index()\n",
    "data_hll"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7560d492",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "ename": "KeyError",
     "evalue": "'hash_name'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/indexes/base.py:3653\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3652\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 3653\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   3654\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/_libs/index.pyx:147\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/_libs/index.pyx:176\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n",
      "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7080\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n",
      "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7088\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;31mKeyError\u001b[0m: 'hash_name'",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[6], line 12\u001b[0m\n\u001b[1;32m     10\u001b[0m fig, axes \u001b[38;5;241m=\u001b[39m plt\u001b[38;5;241m.\u001b[39msubplots(dpi\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m)\n\u001b[1;32m     11\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m column \u001b[38;5;129;01min\u001b[39;00m columns:\n\u001b[0;32m---> 12\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m hash_name \u001b[38;5;129;01min\u001b[39;00m \u001b[43mdata_hll\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mhash_name\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241m.\u001b[39munique():\n\u001b[1;32m     13\u001b[0m         filtered \u001b[38;5;241m=\u001b[39m data_hll[data_hll\u001b[38;5;241m.\u001b[39mbits \u001b[38;5;241m==\u001b[39m bits]\n\u001b[1;32m     14\u001b[0m         linestyle \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m-\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m column \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msquared_error_hll\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m--\u001b[39m\u001b[38;5;124m\"\u001b[39m\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/frame.py:3760\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3758\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_single_key:\n\u001b[1;32m   3759\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m-> 3760\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_getitem_multilevel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   3761\u001b[0m     indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mget_loc(key)\n\u001b[1;32m   3762\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/frame.py:3815\u001b[0m, in \u001b[0;36mDataFrame._getitem_multilevel\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3813\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_getitem_multilevel\u001b[39m(\u001b[38;5;28mself\u001b[39m, key):\n\u001b[1;32m   3814\u001b[0m     \u001b[38;5;66;03m# self.columns is a MultiIndex\u001b[39;00m\n\u001b[0;32m-> 3815\u001b[0m     loc \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   3816\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(loc, (\u001b[38;5;28mslice\u001b[39m, np\u001b[38;5;241m.\u001b[39mndarray)):\n\u001b[1;32m   3817\u001b[0m         new_columns \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns[loc]\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/indexes/multi.py:2812\u001b[0m, in \u001b[0;36mMultiIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   2809\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m mask\n\u001b[1;32m   2811\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(key, \u001b[38;5;28mtuple\u001b[39m):\n\u001b[0;32m-> 2812\u001b[0m     loc \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_level_indexer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlevel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m   2813\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m _maybe_to_slice(loc)\n\u001b[1;32m   2815\u001b[0m keylen \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlen\u001b[39m(key)\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/indexes/multi.py:3160\u001b[0m, in \u001b[0;36mMultiIndex._get_level_indexer\u001b[0;34m(self, key, level, indexer)\u001b[0m\n\u001b[1;32m   3157\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mslice\u001b[39m(i, j, step)\n\u001b[1;32m   3159\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 3160\u001b[0m     idx \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_loc_single_level_index\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlevel_index\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   3162\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m level \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_lexsort_depth \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m   3163\u001b[0m         \u001b[38;5;66;03m# Desired level is not sorted\u001b[39;00m\n\u001b[1;32m   3164\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(idx, \u001b[38;5;28mslice\u001b[39m):\n\u001b[1;32m   3165\u001b[0m             \u001b[38;5;66;03m# test_get_loc_partial_timestamp_multiindex\u001b[39;00m\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/indexes/multi.py:2752\u001b[0m, in \u001b[0;36mMultiIndex._get_loc_single_level_index\u001b[0;34m(self, level_index, key)\u001b[0m\n\u001b[1;32m   2750\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m\n\u001b[1;32m   2751\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 2752\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mlevel_index\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/miniconda3/envs/py38/lib/python3.8/site-packages/pandas/core/indexes/base.py:3655\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3653\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_engine\u001b[38;5;241m.\u001b[39mget_loc(casted_key)\n\u001b[1;32m   3654\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n\u001b[0;32m-> 3655\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m   3656\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[1;32m   3657\u001b[0m     \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[1;32m   3658\u001b[0m     \u001b[38;5;66;03m#  InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[1;32m   3659\u001b[0m     \u001b[38;5;66;03m#  the TypeError.\u001b[39;00m\n\u001b[1;32m   3660\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n",
      "\u001b[0;31mKeyError\u001b[0m: 'hash_name'"
     ]
    },
    {
     "data": {
      "image/png": "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AgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAA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AAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDEHdTdA7THihUrYsmSJbF69epoamqKgQMHxsiRI6OysjKKi4u7e7zYtWtXPP/881FdXR0NDQ2xc+fOKC0tjcMOOyxGjRoVI0eOjB49tDkAAAAAAKAwFXQwqqqqiu9+97vxwgsv7PHvpaWlMW3atLjyyiujrKzsAE8XsXLlyrjxxhvjnnvuiY0bN+71uUMOOSTGjx8fX/7yl+P0008/cAMCAAAAAAC0Q0G+9rJjx46YOnVqTJ48ea+xKCJi8+bNMWfOnBg9enQ8+eSTB2y+5ubmuPbaa2PUqFFx22237TMWRUS88cYbMX/+/LjrrrsOzIAAAAAAAAAdUHBvGDU3N8fZZ58d8+fPz+z37Nkzhg4dGv3794+VK1fGpk2bcn9bt25dfOITn4jHHnssTjjhhC6db+fOnfHZz3427r333t3+1r9//3j3u98dhxxySDQ2NsYrr7wSW7du7dJ5AAAAAAAAOqvg3jC68cYbd4tFF154YdTV1UVtbW0sXbo0Xnvttbjvvvti6NChuWe2bt0aU6ZMyYSkrnD++ednYtFBBx0UX/va12LJkiXx+uuvx/Lly2Px4sVRXV0djY2NsXz58vjBD34QlZWVUVRU1KWzAQAAAAAA7I+ilpaWlu4e4h82bNgQhx9+eDQ2Nub2rr322vj2t7+9x+fr6+vjIx/5SKxatSq3953vfCdmzZrVJfPdfffd8bnPfS63rqioiIcffjiOOeaYdp1//fXXY+DAgV0yW3stW7Ysjj766Nz6pZdeiqOOOqobJwIAAAAAgO6X+n8/L6g3jG644YZMLDrppJNixowZe31+8ODBcfvtt2f2brnlltiwYUPeZ1u/fn1861vfyq379+8fCxcubHcsiohuj0UAAAAAAAB7UjDBqLm5Oe64447M3lVXXdXm17idcsopceKJJ+bWjY2NMXfu3LzPd80118T69etz6+9973sxYsSIvH8OAAAAAADAgVYwwWjRokWxbt263PqII46Ik08+uV1nzz///My6qqoqj5NF7NixI+66667c+l3veld85StfyetnAAAAAAAAdJeCCUYPPvhgZn3qqae2+XbRm599swULFsSWLVvyNtuvf/3reO2113Lrc845J3r27Jm3+wEAAAAAALpTwQSjF198MbOurKxs99mKiooYPnx4bt3U1BTV1dV5mmz3mDV+/Pi83Q0AAAAAANDdCiYYLV++PLMePXp0h863fr71fZ3x7LPPZtbvf//7IyJi165d8fDDD8c555wT73vf+6KkpCQGDBgQ733ve2PKlClxxx13xNatW/M2BwAAAAAAQFc4qLsHiIjYtm1b1NXVZfaGDBnSoTtaP//yyy93eq6IiE2bNsX//u//5tY9e/aMYcOGRW1tbUydOjWeeeaZPZ6pqamJe++9Ny6//PK47rrr4nOf+1xe5gEAAAAAAMi3gnjDaP369dHS0pJb9+rVK8rLyzt0x+DBgzPrhoaGvMxWW1ubma1fv35RXV0dxx577B5jUWtr1qyJz3/+8/Htb387L/MAAAAAAADkW0G8YbR58+bMum/fvlFUVNShO0pKSvZ55/7auHFjZl1UVBQTJ06MTZs2RcTfZz333HPjpJNOikGDBsWGDRti4cKF8ctf/jK2bduWO3f99dfH4MGD4xvf+EZe5or4exRbt25dh87U1NTk7fMBAAAA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nGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAA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OMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAAAACAxAlGAAAAAAAAiROMAAAAAAAAEicYAQAAAAAAJE4wAgAAAAAASJxgBAAAAAAAkDjBCAAAAAAAIHGCEQAAAAAAQOIEIwAAAAAAgMQJRgAAAAAAAIkTjAAAAAAAABInGAEAAAAAACROMAIAAAAAAEicYAQAAAAAAJA4wQgAAAAAACBxghEAAAAAAEDiBCMAAAAAAIDECUYAAAAAAACJE4wAAAAAAAASJxgBAAAAAAAkTjACAAAAAABInGAEAAAAAACQOMEIAAAAAAAgcYIRAAAAAABA4gQjAAAA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AAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5wRGAAAAAAAAOScwAgAAAAAAyDmBEQAAAAAAQM4JjAAAAAAAAHJOYAQAAAAAAJBzAiMAAAAAAICcExgBAAAAAADknMAIAAAAAAAg5/bq6gLa49VXX4358+fHihUrYvPmzbHffvvFYYcdFmPHjo3KysouqytJkliwYEE8//zz0djYGBERAwcOjCOPPDJGjx4dhUKhy2oDAAAAAABor0wHRvfdd1/8+7//eyxYsGCb3+/du3ece+65cfXVV0dNTU3Z6tqyZUt85zvfiVmzZkVDQ8M25wwePDguvvji+Jd/+Zfo2bNn2WoDAAAAAADoqEw+km7Tpk1x9tlnx6RJk7YbFkVErFu3Lr773e/GiBEj4ne/+11Zanv99dfjox/9aFx22WXbDYsiIlasWBH/+q//GmPGjNnhPAAAAAAAgK6WucCopaUlzjjjjPjpT3+aOt6jR4844IADYtSoUdG3b9/U91atWhWf/OQn46mnnurU2hobG2P8+PHx3HPPpY5XVVXFEUccEYcffnibR+Q9++yzMX78+Fi9enWn1gYAAAAAALCrMhcY3XDDDXH//fenjp1//vmxfPnyWLJkSTz33HPx9ttvxz333BNDhw4tzlm/fn1Mnjw53nnnnU6r7dxzz41XX321OK6srIxZs2bF6tWr46WXXor6+vpYvXp13HTTTang6M9//nOcd955nVYXAAAAAADA7shUYPTWW2/Ft771rdSxa6+9Nm655Zaora0tHquoqIhJkybFvHnzYtiwYcXjK1asiJtuuqlTavvNb34TDz30UHHcs2fPePjhh+Oiiy6KXr16FY9XV1fHJZdcEr/+9a9T7y76xS9+EXPmzOmU2gAAAAAAAHZHpgKjGTNmxNq1a4vj4447Lr761a9ud/6gQYPi+9//furYzJkz46233ip5bV//+tdT4yuuuCKOO+647c7/2Mc+1qb2q666quR1AQAAAAAA7K7MBEYtLS3xwx/+MHXsmmuuiUKhsMN1J5xwQhx77LHF8dq1a+Ouu+4qaW1//OMfY/78+cVxdXV1XHbZZTtdd/nll0d1dXVxPG/evFi0aFFJawMAAAAAANhdmQmM5s2bF6tWrSqODzzwwDj++OPbtfYLX/hCanzfffeVsLJo806lyZMnR58+fXa6rk+fPvGZz3wmdazUtQEAAAAAAOyuzARGv/zlL1PjE088cad3F209d2tz586NpqamTqttwoQJ7V7burYHH3ywJDUBAAAAAACUSmYCo+effz41Hjt2bLvX1tbWxrBhw4rjzZs3R319fUnqSpIkXnzxxV2ubdy4canxCy+8EEmSlKQ2AAAAAACAUshMYNT63T4jRozo0PrW80v1rqBly5bF+vXri+Pq6uoYOnRou9fX1dVFr169iuOmpqZ4/fXXS1IbAAAAAABAKWQiMNqwYUMsX748dWzIkCEd2qP1/Jdffnm369rWPh2ta1trSlUbAAAAAABAKWQiMFq9enXqMW09e/aMAQMGdGiPQYMGpcaNjY0lqa31PoMHD+7wHp1VGwAAAAAAQCns1dUFRESsW7cuNe7Vq1cUCoUO7VFdXb3DPXdV631an6c9Oqu2xsbGWLVqVYfWtH630+LFi0tSCwAAAAAA7MlaXy/ftGlTF1XSNTIZGFVWVnZ4j6qqqh3uuauyXNv3vve9mDZt2m7t8alPfaoktQAAAAAAQHfy+uuvx+jRo7u6jLLJxCPpNm7cmBrvvffeHd5jn332SY03bNiwWzW9J8u1AQAAAAAAnWPNmjVdXUJZZSIwan3XzubNmzu8R+tbw3blTqBtyXJtAAAAAABA53j33Xe7uoSyysQj6Xr37p0at76rpz1a37XTes9dleXapk6dGp/5zGc6tOb555+Ps88+uzi+6667YsSIESWpB2B3LV68OPWozPvuuy+GDx/edQUBtKJPAVmmRwFZp08BWVdfXx+TJ08ujj/84Q93YTXll8nAaP369ZEkSRQKhXbv0dTUtMM9S1Vb6/O0R2fVNmDAgBgwYMBu7TFixIg44ogjSlIPQKkNHz5cjwIyTZ8CskyPArJOnwKybt999+3qEsoqE4+kq6mpSYVDW7ZsicbGxg7t0dDQkBrvbpCyvX1WrFjR4T06qzYAAAAAAIBSyERgVFVVFUOHDk0dW758eYf2aD3/sMMO2+26IiIOPfTQ1Pj111/v8B6t15SqNgAAAAAAgFLIRGAU0TZEqa+v79D6RYsW7XC/XVVXVxdVVVXFcVNTUyxbtqzd65ctWxbr168vjqurq2PIkCElqQ0AAAAAAKAUMhMYjRo1KjWeN29eu9e+8cYb8dprrxXHPXv2jBEjRpSkrkKhECNHjtzl2p588snUeOTIkR16NxMAAAAAAEBny0xgdPLJJ6fGjz76aCRJ0q61v/nNb1Lj8ePHR+/evTuttkceeaTda1vPPeWUU0pSEwAAAAAAQKlkJjAaO3Zs1NTUFMdLliyJuXPntmvtD37wg9T4tNNOK2Vpceqpp6bGs2fPjnXr1u103dq1a2P27NmdWhsAAAAAAMDuykxgVFFREeeee27q2LRp03Z6l9Fvf/vbeOKJJ4rjPn36xOTJk0ta28iRI+Poo48ujtetWxczZszY6boZM2ZEU1NTcXzMMceU7FF5AAAAAAAApZKZwCgi4qtf/WrqUXKPP/54XH/99dud39DQEF/84hdTxy666KLUnUrbUigUUl/tuZPpm9/8Zmp83XXXxe9+97vtzt9W7dOnT9/peQAAAAAAAMotU4FRTU1NfO1rX0sdu/LKK2Pq1KmxcuXK4rGWlpa47777YuzYsfHaa68Vj9fW1sall17aKbV94hOfiAkTJhTHW7ZsiY9//OPxne98J9avX1883tTUFLNmzYpPfOITsWXLluLxiRMnxgknnNAptQEAAAAAAOyOTAVGEX+7y+jkk09OHbvlllti6NChcdBBB8Xo0aOjf//+MWnSpFi+fHlxTlVVVdx1113Rr1+/Tqvtxz/+cRxwwAHF8caNG+Piiy+Ompqa+OAHPxhHHHFE1NTUxCWXXBIbN24szjvooIPi9ttv77S6AAAAAAAAdkfmAqOKioqYPXt2nHnmmanjzc3NsWTJknjuuedizZo1qe/1798/fvWrX8W4ceM6tbaBAwfGnDlz4sgjj0wd37BhQyxcuDDq6+tTQVFExKhRo2LOnDmx//77d2ptAAAAAAAAu2qvri5gWyorK+NnP/tZ/MM//ENMnz49nn/++W3Oq66ujilTpsTVV18dAwYMKEttdXV1MX/+/Jg1a1Z85zvfST0qb2u1tbVx8cUXx0UXXRR77713WWprj/333z+uvvrq1BggK/QoIOv0KSDL9Cgg6/QpIOvy3qcKSZIkXV3EzixevDiefvrpaGhoiM2bN0e/fv3i8MMPj3HjxkVlZWWX1dXS0hLPPvtsvPDCC9HY2BgREQMGDIhRo0bF6NGjo6IiczdwAQAAAAAAtLFHBEYAAAAAAAB0HrfAAAAAAAAA5JzACAAAAAAAIOcERgAAAAAAADknMAIAAAAAAMg5gREAAAAAAEDOCYwAAAAAAAByTmAEAAAAAACQcwIjAAAAAACAnBMYAQAAAAAA5JzACAAAAAAAIOcERgAAAAAAADknMAIAAAAAAMi5vbq6ALbv1Vdfjfnz58eKFSti8+bNsd9++8Vhhx0WY8eOjcrKyi6rK0mSWLBgQTz//PPR2NgYEREDBw6MI488MkaPHh2FQqHLagPKK2t9asuWLfHyyy/HwoUL480334y1a9dG7969o3///jFy5Mj44Ac/GBUVPisBeZG1HgXQWtb7VHNzczz77LNRX18fjY2NsWXLlujdu3cMHjw4Dj/88DjssMP82wq6uaz2qTVr1sQzzzwTS5cujTVr1kRLS0v07ds3Bg8eHEcffXS8//3v77LaAPbo6+cJmXPvvfcmo0ePTiJim1+9e/dOvvSlLyWrVq0qa12bN29ObrjhhmTQoEHbrW3w4MHJjTfemGzevLmstQHllaU+tWTJkmTGjBnJiSeemFRVVW23pohI+vbtm1x44YXJK6+80ul1AV0nSz2qPZqampKDDjqoTZ1Tpkzp6tKATpL1PrVkyZLkggsuSPr167fDf1vtu+++yWmnnZb88pe/7JI6gc6T1T7185//PBk/fnxSKBR22J8+9KEPJbfeemuyZcuWstYHdL4VK1Yk99xzT/LVr341GT9+fNKnT5/Un/+6urouq607XD8XGGXIxo0bk8997nM7/Atv66/9998/efzxx8tS2/Lly5MPfehD7a7tqKOOSlasWFGW2oDyyVKf2rhxY/LRj3603bVs/bX33nsnN9xwQ9LS0tIptQFdI0s9qiMuueSSbdYnMILuJ+t9qrm5Ofn2t7+d7LPPPh36t9UZZ5xRthqBzpXVPrV69epk4sSJHf6/31FHHZX8+c9/7vT6gM71+9//Ppk0aVJSW1u70z/3XRUYdZfr54UkSZKgy7W0tMSnP/3puP/++1PHe/ToEUOHDo2+ffvG0qVL45133kl9v1evXvHoo4/GmDFjOq22xsbGGDt2bLz66qup41VVVXHggQdGS0tLLF26NDZu3Jj6/sEHHxzz5s2LmpqaTqsNKJ+s9al169ZFnz59tvm9ysrK+MAHPhA1NTXR1NQUixcvjs2bN7eZN3Xq1Lj55ptLWhfQNbLWo9pr/vz5MWbMmGhpaWnzvSlTpsTtt99e/qKATpH1PrVly5b43Oc+F7Nnz27zvb59+8YHPvCB2HfffWPt2rWxbNmyWL9+ffH7Z5xxRvz3f/93p9YHdL6s9ql33303xo8fHwsWLGjzvf333z+GDBkShUIhGhoa4i9/+UubOYMHD44nnngihg0b1in1AZ1v1qxZcckll7Rrbl1dXbz22mudW1Ar3er6eVcnVvzNdddd1yZlPP/885OGhobinObm5uSee+5Jhg4d2uY2tjVr1nRabZ/85CdT56usrExmzZqVNDU1FeesW7cuuemmm5LKysrU3FNOOaXT6gLKK2t9au3atalzHHDAAck111yTPPnkk21u612/fn1yxx13JHV1dW1+Df/5n/9Z0rqArpG1HtUemzZtSj74wQ8W66iurnaHEXRjWe9T55xzTuqce+21V3LhhRcm8+fPb3NXdnNzc7Jo0aJk1qxZydixY5MzzzyzU2sDyiOrferCCy9sU9epp56aLFiwoM3c+vr6bd4hdeKJJ3ZKbUB5zJw5c7t36vTu3bvL7zDqTtfPBUYZsHr16jbPWrz22mu3O3/FihXJsGHDUvO/8Y1vdEptDz/8cOo8PXv23OGtxnPnzk169uyZWvPYY491Sm1A+WSxT70XGI0bNy55+OGH2/V4ubfffjs5+uijU3X169cveeutt0paG1BeWexR7XH11VcXzz9o0KDkK1/5isAIuqms96k77rgjda7a2trkhRdeaPf6t99+u9NqA8ojq33qzTffTHr06JE6zwUXXLDTdd/85jfbXFSeN29eyesDyuO9wKhPnz7J8ccfn1x22WXJ7Nmzk9deey2ZM2dOlwZG3e36ucAoAy6//PLUD8hxxx230wufjz76aGpNnz59ktWrV5e8to985COp83z961/f6ZqrrroqtWbs2LElrwsoryz2qU2bNiUPPvhgh9c1NDS0+RT/f/3Xf5WsLqD8stijduall15K9t577+L577333lSAJDCC7iXLfWrVqlVJTU1N8Tx9+/b1vg/Ioaz2qR/84Aepc+y///6pT+xvT3Nzc3L44Yen1l555ZUlrQ0on8WLFycLFy5Mmpub23yvqwOj7nb9vCLoUi0tLfHDH/4wdeyaa66JQqGww3UnnHBCHHvsscXx2rVr46677ippbX/84x9j/vz5xXF1dXVcdtllO113+eWXR3V1dXE8b968WLRoUUlrA8onq31q7733jpNOOqnD62pra2PKlCmpYw8//HCpygLKLKs9akdaWlriC1/4QvHdapMmTYpPfepTZTk3UH5Z71Pf+ta3YvXq1cXxt7/97Rg+fHjJzwNkV5b71Msvv5waf/zjH49evXrtdF1FRUVMmjQpdWzx4sUlrQ0on4MOOihGjBgRFRXZijO64/XzbP0O59C8efNi1apVxfGBBx4Yxx9/fLvWfuELX0iN77vvvhJWFm1ecjh58uTtvmB+a3369InPfOYzqWOlrg0onyz3qV219X9qIiKWL1/eRZUAu2tP7FGzZs2Kp59+OiIi9t133/jud79blvMCXSPLfWrTpk3x4x//uDh+//vfH//8z/9c0nMA2ZflPvX222+nxkOGDGn32qFDh6bGa9asKUVJAEXd8fq5wKiL/fKXv0yNTzzxxJ1+gmPruVubO3duNDU1dVptEyZMaPfa1rU9+OCDJakJKL8s96ldtd9++6XG77zzThdVAuyuPa1HLVmyJL7+9a8Xx9dee23U1tZ26jmBrpXlPnXvvfemLsaeeeaZ0aNHj5LtD+wZstyn+vbtmxpv2LCh3Wtbz62pqSlJTQDv6Y7XzwVGXez5559PjceOHdvutbW1tTFs2LDiePPmzVFfX1+SupIkiRdffHGXaxs3blxq/MILL0SSJCWpDSivrPap3dHQ0JAa9+/fv4sqAXbXntaj/umf/inWr18fERFjxoyJCy64oFPPB3S9LPep1hc5xo8fX7K9gT1HlvvUqFGjUuNnnnmm3Wu3fkxURMRHPvKRUpQEEBHd9/q5wKiLtX424YgRIzq0vvX8Uj3rcNmyZcWLGRF/e/5i61t5d6Suri71TNmmpqZ4/fXXS1IbUF5Z7VO744knnkiNDznkkC6qBNhde1KP+v73vx+PPfZYRET07NkzbrvttnZ/ehfYc2W5T7W+8HrkkUdGRERzc3M89NBDceaZZ8ahhx4a1dXV0a9fvzj44INj8uTJ8cMf/jD1/0Vgz5blPnXyySen3vPx5JNPxlNPPbXTdYsXL46f//znxXFlZWWcddZZJasLoLtePxcYdaENGza0eW9GR57Fuq35rV8GuKta79PRura1plS1AeWT5T61q9599924++67U8cmTpzYRdUAu2NP6lFvvPFG6uWnl19+eRxxxBGdci4gO7Lcp95555145ZVXiuMePXpEXV1dLFmyJI499tiYOHFi/M///E+88sorsX79+njnnXdi8eLFMXv27DjvvPPi4IMPjjvuuKMktQBdJ8t9KiKiX79+8bWvfS117PTTT9/hnUaLFi2KiRMnxubNm4vHpk+fHgMGDChZXQDd9fr5Xl1dQJ6tXr06dZtZz549O/yX16BBg1LjxsbGktTWep/Bgwd3eI9BgwalfshLVRtQPlnuU7tq+vTpsW7duuK4pqYmTj755C6sCNhVe1KPmjp1avFFywcffHBcddVVnXIeIFuy3KeWLFmSqq1Pnz5RX18fY8eObdf7HVeuXBn/+I//GAsXLozrrruuJDUB5ZflPvWeK664IhYuXBh33nlnRPztgzhjxoyJk046KSZMmBB1dXVRKBSioaEhHnvssbjnnntiy5YtqfWXXnppSWsC6K7XzwVGXWjrC5YREb169erwY0m2vi13W3vuqtb7tD5Pe3RWbUD5ZLlP7Yp58+bFTTfdlDp21VVXpW4BBvYce0qPuuuuu+K+++4rjm+99daorKws+XmA7Mlyn3ovxH5PoVCIk08+uRgW9erVK84666w47rjjon///vHWW2/F448/HnfeeWfqRfLXX399DBo0KL785S+XpC6gvLLcp95TUVERP/nJT2Ls2LExbdq0WLVqVTQ3N8cDDzwQDzzwwHbXjRs3LqZNmxYnnHBCSesBiOi+1889kq4Ltf4B2JULB1VVVTvcc1dluTagfLpTL2hsbIwzzzwzmpubi8eOPvro+NKXvtQl9QC7b0/oUW+99VbqIurnP/95L5WHHMlyn2odGP31r3+NpUuXRkTEUUcdFYsWLYrbbrstzjnnnJg4cWKcc8458f3vfz/q6+tj5MiRqbWXXXZZ6vF2wJ4jy31qa4VCIS688MJYsGBBu54QMW7cuLj00kv9uwvoNHtK/+wogVEX2rhxY2q89957d3iPffbZJzXe+pNeuyPLtQHl0116waZNm2LSpEmplwf26dMn7rzzzujRo0fZ6wFKY0/oURdffHHxsQIDBgyIG2+8saT7A9mW5T61vQsSgwcPjkceeWS7L20eNmxY/Pa3v433v//9xWObNm3S32APleU+tbWmpqb4yle+Eoccckg8+OCDO53/5JNPxqc//ek44ogj4n//939LXg/AntI/O0pg1IVap45bv4yvvTZt2rTDPXdVlmsDyqc79IKWlpY4++yzY968ecVjPXr0iJ/+9KcxfPjwstYClFbWe9RDDz0UP/nJT4rjmTNnxvve976S7Q9kX5b71Pb2ueGGG2K//fbb4dqampo27y264447MnGRA+iYLPep96xcuTI+/OEPx8yZM4t95tBDD43vfe978ac//SnWrVsX69evj1dffTVuv/32OOqoo4pr//SnP8Wxxx6bejwwQCnsCf1zVwiMulDv3r1T49apZHu0/gd56z13VZZrA8qnO/SCqVOnxt13310cFwqFuO222+KUU04pax1A6WW5R61duzbOP//84vgTn/hEnHXWWSXZG9hzZLlPbWuf973vfXH66ae3a/0ZZ5wRffv2LY43btwY8+fPL0ltQPlkuU9F/K2eCRMmxJ/+9KfisS9+8Yvx4osvxgUXXBCHHnpoVFdXR1VVVRx44IExZcqUeOaZZ+Lf/u3fivP/7//+Lz772c/GokWLSlYXQNb7564SGHWh1j8A69evjyRJOrRHU1PTDvfcVa33aX2e9uis2oDyyXKfao8rr7wybr311tSx//iP/4jPf/7zZasB6DxZ7lFXXHFFLF++PCL+9vLoW265pST7AnuWLPepbe0zZsyY6NmzZ7vWV1ZWxkc+8pHUsT/84Q8lqQ0onyz3qYiI66+/PhYuXFgc//3f/33ceuutO3z0U6FQiOnTp8c555xTPLZx48a49NJLS1YXQHe9fi4w6kI1NTVRKBSK4y1bthSfcd9eDQ0NqfGAAQNKUlvrfVasWNHhPTqrNqB8styndua6665r86iUb3zjG3HJJZeU5fxA58tqj1q6dGkqIJo2bVoMGzZst/cF9jxZ7VMREQMHDmxz7JBDDunQHoceemhq3NFfG9D1stynmpub47vf/W7q2PTp06Oion2XM7/1rW+l5v76179OvdcWYHd01+vnAqMuVFVV1eZFou99ErW9Ws8/7LDDdruuiLb/8N+Vv1BbrylVbUD5ZLlP7cjNN98cV155ZerYRRddFNOmTev0cwPlk9Ue9c4776Q+mXvZZZdFoVDY6VfrHvWjH/0o9f1+/frtdm1AeWW1T0VEHHTQQW0+ob/vvvt2aI/W8//617/udl1AeWW5T7344ouxevXq4rimpiaOOeaYdq8fMmRIHHnkkcVxkiTx+9//viS1AXTX6+cCoy7W+oegvr6+Q+tbP3+1VD9UdXV1UVVVVRw3NTXFsmXL2r1+2bJlsX79+uK4uro6hgwZUpLagPLKap/anh//+Mfx5S9/OXXsvPPOi5kzZ3bqeYGusaf1KCB/stqnevTo0eaOotYvXt6Z1s/q79Wr127XBZRfVvvU0qVLU+Nhw4al7oZqjwMOOCA1bv1pfoBd1V2vnwuMutioUaNS43nz5rV77RtvvBGvvfZacdyzZ88YMWJESeoqFAoxcuTIXa7tySefTI1HjhzZ4b/UgWzIap/alp///Odx3nnnpT7ZP3ny5Ljtttv0IOim9qQeBeRTlvvU6NGjU+M333yzQ+tbP7aqf//+u10TUH5Z7VOtQ+y99tqrw3u0fi9bc3PzbtUE8J7uev1cYNTFTj755NT40UcfbffLBX/zm9+kxuPHjy/pi7Fa1/bII4+0e23ruaecckpJagLKL8t9amsPPfRQnHXWWan/AJx00knxk5/8pN3PuAb2PFnsUcOHD49HHnmkw19bv5g5ImLChAmp799///27XRtQflnsU+859dRTU+Nnn322Q+tbz2/9aBZgz5DVPtU6hF65cmWH92h9R9H++++/WzUBbK1bXj9P6FLNzc1JTU1NEhHFr8cee6xda4899tjUuptvvrmktb3wwgup/Xv37p2sXbt2p+vefffdpLq6OrV24cKFJa0NKJ8s96n3zJ07N6mqqkqda/z48cmGDRs65XxAduwJPaq9rr766lQ9U6ZM6dJ6gNLIcp9at25dUllZmTrHK6+80q61L730UmpdRCRvvvlmSesDyiOrferll19u02cWL17c7vXvvvtuss8++6TWz507t2T1AdkwZ86c1J/zurq6sp27O14/95HrLlZRURHnnntu6ti0adN2+kmO3/72t/HEE08Ux3369InJkyeXtLaR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",
      "text/plain": [
       "<Figure size 1920x1440 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "bits_to_skip = (1, 2, 3, 4, 5)\n",
    "\n",
    "\n",
    "for scale in (\"log\", \"linear\"):\n",
    "    for bits in data_hll[\"bits\"].unique():\n",
    "        if bits in bits_to_skip:\n",
    "            continue\n",
    "        fig, axes = plt.subplots(dpi=300)\n",
    "        for column in columns:\n",
    "            for hash_name in data_hll[\"hash_name\"].unique():\n",
    "                filtered = data_hll[data_hll.bits == bits]\n",
    "                linestyle = \"-\" if column == \"squared_error_hll\" else \"--\"\n",
    "                filtered = filtered[filtered.hash_name == hash_name]\n",
    "                short_hash_name = hash_name.split(\":\")[-1]\n",
    "                if len(data_hll[\"hash_name\"].unique()) == 1:\n",
    "                    short_hash_name = \"\"\n",
    "                c = column.split(\"_\")[-1]\n",
    "                plt.errorbar(\n",
    "                    filtered.memory,\n",
    "                    filtered[column][\"mean\"],\n",
    "                    filtered[column][\"std\"],\n",
    "                    linestyle=linestyle,\n",
    "                    #marker=hash_name_marker_style[short_hash_name],\n",
    "                    label=f\"{bits}b, {c}, {short_hash_name}\",\n",
    "                    alpha=0.5\n",
    "                )\n",
    "\n",
    "        plt.legend()\n",
    "        plt.xscale(\"log\")\n",
    "        plt.yscale(scale)\n",
    "        plt.ylabel(\"Cardinality MSE over 1000 random sets\")\n",
    "        plt.xlabel(f\"Memory required ({bits}b)\")\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b147a27",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}